import com.zelix.um;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;

import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

@Aspect
public class ZkmAjc {

    /**
     * private static String b(int var0, int var1, int var2)
     * @param point
     */
//    @AfterReturning(pointcut = "execution(String *.*(int, int, int))", returning = "retStr")
    public void zkmPrintStringArgs3i(JoinPoint point, String retStr) {
        System.out.println("----------------------------------");
        System.out.println("[zkmPrintStringArgs3i] " + point.getSignature());
        System.out.println("[zkmPrintStringArgs3i] retStr : " + retStr);
//        Object[] args = point.getArgs();
//        if (args != null) {
//            for (int i = 0; i < args.length; i++) {
//                if (args[i] != null) {
//                    System.out.println("[zkmPrintStringArgs3i] " + i + " : " + args[i]);
//                }
//            }
//        } else {
//            System.out.println("[zkmPrintStringArgs3i] args : " + args);
//        }

        if (retStr.contains("Evaluation has expired")) {
            new RuntimeException().printStackTrace();
            Object[] args = point.getArgs();
            if (args != null) {
                for (int i = 0; i < args.length; i++) {
                    if (args[i] != null) {
                        System.out.println("[zkmPrintStringArgs3i] " + i + " : " + args[i]);
                    }
                }
            } else {
                System.out.println("[zkmPrintStringArgs3i] args : " + args);
            }
        }
    }

    /**
     * public static String[] b()
     */
//    @AfterReturning(pointcut = "execution(String com.zelix.um.*(..))", returning = "retStr")
    public void um(JoinPoint point, String retStr) {
        System.out.println("******************");
        System.out.println("[um] " + point.getSignature());
        System.out.println("[um] retStrings : " + retStr);

//        if (retStr.startsWith("none")) {
//            System.out.println("["+retStr+"]");
//            for (Field field : um.class.getDeclaredFields()) {
//                field.setAccessible(true);
//                System.out.println("[um] field[" + field.getName() + "] : " + field.getType());
//                try {
//                    Object fieldValue = field.get(point.getThis());
//                    System.out.println("fieldVaule : " + fieldValue);
//                    if (fieldValue != null && fieldValue instanceof String[]) {
//                        String[] strs = (String[]) fieldValue;
//                        for (int i = 0; i < strs.length; i++) {
//                            System.out.println("str["+i+"] : " + strs[i]);
//                        }
//                    }
//
//                } catch (Throwable e) {
//
//                }
//            }
//        }

//        Object[] args = point.getArgs();
//        if (args != null) {
//            for (int i = 0; i < args.length; i++) {
//                if (args[i] != null) {
//                    System.out.println("[zkmPrintStringArgs3i] " + i + " : " + args[i]);
//                }
//            }
//        } else {
//            System.out.println("[zkmPrintStringArgs3i] args : " + args);
//        }
//
//        new RuntimeException(point.getSignature().toString()).printStackTrace();
    }

//    @AfterReturning(pointcut = "execution(int com.zelix.s.*())", returning = "ret")
    public void s_reti(JoinPoint point, int ret) {
        System.out.println("******************");
        System.out.println("[s_reti] " + point.getSignature());
        System.out.println("[s_reti] ret : " + ret);
    }

//    @After("execution(void com.zelix.s.*(..))")
    public void s_setx(JoinPoint point) {
        System.out.println("******************");
        System.out.println("[s_reti] " + point.getSignature());
        printAgrs("[s_reti]", point);
    }

//    @AfterReturning(pointcut = "execution(int com.zelix._s.*())", returning = "ret")
    public void _s_reti(JoinPoint point, int ret) {
        System.out.println("******************");
        System.out.println("[_s_reti] " + point.getSignature());
        System.out.println("[_s_reti] ret : " + ret);
    }

//    @After("execution(void com.zelix._s.*(..))")
    public void _s_setx(JoinPoint point) {
        System.out.println("******************");
        System.out.println("[_s_reti] " + point.getSignature());
        printAgrs("[_s_reti]", point);
    }

//    @After("execution(* com.zelix.as.*(..))")
    public void as_setx(JoinPoint point) {
        System.out.println("******************");
        System.out.println("[as_reti] " + point.getSignature());
        printAgrs("[as_reti]", point);
        printFiels("[as_reti]", point);
    }

    public static void printAgrs(String tip, JoinPoint point) {
        Object[] args = point.getArgs();
        if (args != null) {
            for (int i = 0; i < args.length; i++) {
                Object arg = args[i];
                System.out.println(tip + " " + i + " : " + arg);
                if (arg instanceof Object[]) {
                    Object[] arg2 = (Object[]) arg;
                    for (int j = 0; j < arg2.length; j++) {
                        System.out.println(">>>>" + tip + " " + j + " : " + arg2[j]);
                    }
                }
            }
        } else {
            System.out.println(tip + " args : " + args);
        }
    }

    public static void printFiels(String tip, JoinPoint point) {
        Object thiz = point.getThis();
        Field[] fields = thiz.getClass().getDeclaredFields();
        for (Field field : fields) {
            field.setAccessible(true);
            try {
                Object fieldValue = field.get(thiz);
                System.out.println(tip + " filed["+field.getName()+"] : " + fieldValue);
            } catch (Throwable e) {

            }

        }
    }

//    @Before("call(java.text.SimpleDateFormat.new(..))")
//    public void callSimpleDateFormat(JoinPoint point) {
//        System.out.println("******************");
//        System.out.println("[callSimpleDateFormat] " + point.getSignature());
//        printAgrs("[callSimpleDateFormat]", point);
//        new RuntimeException().printStackTrace();
//    }

//    @Before("call(String java.text.SimpleDateFormat.format(..))")
    public void callSimpleDateFormat_format(JoinPoint point) {
        System.out.println("******************");
        System.out.println("[callSimpleDateFormat_format] " + point.getSignature());
        printAgrs("[callSimpleDateFormat_format]", point);
        new RuntimeException().printStackTrace();
    }

    /**
     * 构造方法注意点
     * 1. 无返回值
     * 2. 方法名是 new
     * @param point
     * @return
     */
//    @Around("call(java.util.Date.new(..)) && within(com.zelix..*)")
    public Date aroudDate(ProceedingJoinPoint point) throws Throwable {
        System.out.println("******************");
        System.out.println("[aroudDate] " + point.getSignature());
        printAgrs("[aroudDate]", point);
        new RuntimeException().printStackTrace();
        try {
            Date date = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse("2018-01-01 12:12:12");
            System.out.println("[aroudData] is " + date);
            return date;
        } catch (ParseException e) {
            System.out.println("[aroudData] ParseException ");
            e.printStackTrace();
            return (Date) point.proceed(point.getArgs());
        }
    }

//    @Around("call(long java.lang.System.currentTimeMillis()) && within(com.zelix..*)")
    public long modifyCurrentTimeMillis(ProceedingJoinPoint point) throws ParseException {
        System.out.println("******************");
        System.out.println("[modifyCurrentTimeMillis] " + point.getSignature());
//        System.currentTimeMillis();
        Date date = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse("2018-01-01 12:12:12");
        long time = date.getTime();
        System.out.println("[modifyCurrentTimeMillis] " + time);
        return time;
    }

    //@Around("call(boolean java.util.Date.after(..)) && within(com.zelix..*)")
    public boolean date_after(ProceedingJoinPoint point) throws Throwable {
        System.out.println("******************");
        System.out.println("[date_after] " + point.getSignature());
        System.out.println("[date_after] thiz" + point.getThis());
        printAgrs("[date_after]", point);

        Object proceed = point.proceed(point.getArgs());
        System.out.println("[date_after] ret " + proceed);

        return (boolean) proceed;
    }

    //@Around("call(boolean java.util.Date.before(..)) && within(com.zelix..*)")
    public boolean date_before(ProceedingJoinPoint point) throws Throwable {
        System.out.println("******************");
        System.out.println("[date_before] " + point.getSignature());
        System.out.println("[date_before] thiz" + point.getThis());
        printAgrs("[date_before]", point);

        Object proceed = point.proceed(point.getArgs());
        System.out.println("[date_before] ret " + proceed);

        return (boolean) proceed;
    }

//    @Before("call(* java.util.Date.*(..)) && within(com.zelix..*)")
    public void date_all(JoinPoint point) {
        System.out.println("******************");
        System.out.println("[date_all] " + point.getSignature());
        System.out.println("[date_all] thiz : " + point.getThis());
        printAgrs("[date_all]", point);
    }

//    @AfterReturning(pointcut = "call(* java.lang.reflect.Method.invoke(..))", returning = "ret")
    public void Method_invoke(JoinPoint point, Object ret) {
        printAgrsEx("[Method_invoke]", point);
        System.out.println("[Method_invoke] ret : " + ret);
    }

    public static void printAgrsEx(String tip, JoinPoint point) {
        System.out.println("******************");
        System.out.println(tip + " " + point.getSignature());
        System.out.println(tip + " thiz : " + point.getThis());
        System.out.println(tip + " Target : " + point.getTarget());
        printAgrs(tip, point);
    }

    /**
     * ******************
     [Method_invoke] Target : public static long java.lang.Long.parseLong(java.lang.String) throws java.lang.NumberFormatException
     [Method_invoke] ret : 1519304107902
     ******************
     [Method_invoke] Target : public static long com.zelix.lh.a(java.lang.String,int)
     [Method_invoke] ret : 1519304107902
     ******************
     */

    @Around("execution(long com.zelix.lh.a(..))")
    public long aroud_lh_a(ProceedingJoinPoint point) {
        printAgrsEx("[aroud_lh_a]", point);
        return 32503478400000L;
    }

    /**
     * 获取当前时间的格式化
     [Method_invoke] Target : public static java.lang.String com.zelix.cm.d(int)
     >>>>[Method_invoke] 0 : 1430313696
     [Method_invoke] ret : 2018.03.23 18:04:31
     ******************
     */
    @Around("execution(String com.zelix.cm.d(int))")
    public String aroud_cm_d(ProceedingJoinPoint point) {
        printAgrsEx("[aroud_cm_d]", point);
        return "2010.03.23 18:04:31";
    }

    /**
     * [Method_invoke] Object java.lang.reflect.Method.invoke(Object, Object[])
     [Method_invoke] thiz : null
     [Method_invoke] Target : public static java.lang.String com.zelix.cm.b(java.lang.String,java.lang.String,int)
     [Method_invoke] 0 : null
     [Method_invoke] 1 : [Ljava.lang.Object;@67b6d4ae
     >>>>[Method_invoke] 0 : 0d2530ca7683ea77e058827be3637bc51af78f5f89504adfe67b2ba6e6d2c5a59b456848717172a1a6d95f3864f152d483c0e916fdc56da9f3de78e9842c04cf
     >>>>[Method_invoke] 1 : false
     >>>>[Method_invoke] 2 : 2084637436
     [Method_invoke] ret : false
     */


//    @AfterReturning(pointcut = "call(* java.lang.reflect.Field.get(..))", returning = "ret")
    public void Field_get(JoinPoint point, Object ret) {
        printAgrsEx("[Field_get]", point);
        System.out.println("[Field_get] ret : " + ret);
    }

    /**
     * Target : private java.lang.String com.zelix.as.a
     * 等价下面的===
     * class as {
     *     private String a;
     * }
     * @param point
     */
//    @Before("call(* java.lang.reflect.Field.set(..))")
    public void Field_set(JoinPoint point) {
        printAgrsEx("[Field_set]", point);
    }
}
